﻿using System;
using System.Collections.Generic;
using IdentityAtRest.Contracts;
using IdentityAtRest.Utility.Identity.Authorization;
using SimpleExpressionEvaluator;
using SimpleExpressionEvaluator.Parsers.Irony;

namespace IdentityAtRest.Service.Authorization
{
    public class PermissionPolicyRepository : IPermissionPolicyRepository
    {

        //This signature is provided for testing / IoC integration
        public PermissionPolicyRepository(IExpressionEvaluator expressionEval)
        {
            _expressionEval = expressionEval;

            //Below we are setting up some dummy policies. These would normally come from a
            //a persistent store.

            //all logged in users can add monkeys to the shaver. anonymous users will still
            //be rejected, however, because CurrentUser will resolve to null and this
            //expression will never be evaluated.
            AddPermissionPolicy(Permissions.MonkeyShavingService.CanAddMonkeyToShaver, "true");

            //only admins can view unshaved monkeys.
            //This expression could also be IsInRole(Administrator)
            AddPermissionPolicy(Permissions.MonkeyShavingService.CanViewUnshavedMonkeys, "MatchesAny(Role = Administrator)");
            
        }

        public IList<IPermissionPolicy> GetPermissionPolicies(params string[] requestedPermissions)
        {
            var policies = new List<IPermissionPolicy>();
            foreach (string requestedPermission in requestedPermissions)
            {
                //Normally, your policies will be stored in a persistent
                //store, such as a file or a database. An in memory hashtable
                //is used here to keep the sample simple.
                if (_policyStore.ContainsKey(requestedPermission))
                    policies.Add(_policyStore[requestedPermission]);
                else
                {
                    //If no policy is found for the requested permission we'll
                    //create an expression hardcoded to 'false', denying access
                    //- this is just on possible approach, your application logic is likely
                    //to vary, perhaps to return an error instead.
                    policies.Add(CreatePolicy(requestedPermission, "false"));
                }
            }
            return policies;
        }


        public IExpressionEvaluator ExpressionEvaluator
        {
            get { return _expressionEval; }
        }

        private readonly IExpressionEvaluator _expressionEval;

        private readonly Dictionary<string, IPermissionPolicy> _policyStore =
            new Dictionary<string, IPermissionPolicy>(StringComparer.CurrentCultureIgnoreCase);


        private void AddPermissionPolicy(string policyName, string policyExpression)
        {
            _policyStore[policyName] = CreatePolicy(policyName, policyExpression);
        }

        public IPermissionPolicy CreatePolicy(string policyName, string policyExpression)
        {
            return new ExpressionPermissionPolicy(policyName, _expressionEval.CompileExpression<bool>(policyExpression));
        }
    }
}
